home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Magazine / Online / MagPLIP / source / linport.asm < prev    next >
Assembly Source File  |  1998-04-02  |  12KB  |  463 lines

  1. ;
  2. ;  $VER$;
  3. ;  linplip.device - Parallel Line Internet Protocol
  4. ;
  5. ;  Assembler routines for efficient port handling.
  6. ;
  7. ;  Written by Stéphane Zermatten, based on the code written
  8. ;  by Oliver Wagner and Michael Balzer, and modified by 
  9. ;  Marius Gröger. 
  10. ;  
  11. ;  (C) Copyright 1997 Stéphane Zermatten
  12. ;      All Rights Reserved
  13. ;
  14. ;  HISTORY:
  15. ;
  16. ;  1.3 (97.10.26 23:18:33)      -- Protocol changed (once again)
  17. ;                                  to lighten the charge of the
  18. ;                                  68k CPU (I suppose the PC more
  19. ;                                  powerful)
  20. ;  1.2 (97.10.25 16:34:24)      -- Receive protocol changed. 
  21. ;                                  Now, 3 nibbles are used, instead of 4. 
  22. ;  1.1 (97.10.25 08:20:23)      -- initial revision
  23. ;                                  based on a C version of linport
  24. ;
  25. ;  FUTUR CHANGES
  26. ;
  27. ;   I'm working on an interrupt-based version, to see which 
  28. ;   approach is better.    
  29.  
  30.       section "text",code
  31.  
  32.  
  33. ;----------------------------------------------------------------------------
  34.  
  35.  
  36.       IFND HARDARE_CIA_I
  37.       include "hardware/cia.i"
  38.       ENDC
  39.  
  40.       IFND EXEC_MACROS_I
  41.       include "exec/macros.i"
  42.       ENDC
  43.  
  44.       IFND MAGPLIP_I
  45.       include "magplip.i"
  46.       ENDC
  47.  
  48.  
  49. ;----------------------------------------------------------------------------
  50.  
  51.  
  52.       xdef    _interrupt
  53.       xdef    _hwsend
  54.       xdef    _hwrecv
  55.  
  56. ;----------------------------------------------------------------------------
  57.  
  58. ciaa     equ     $bfe001
  59. ciab     equ     $bfd000
  60. BaseAX   equ     ciab+ciapra
  61.  
  62. OutReg   equ     ciaa+ciaprb
  63. StatusReg equ    ciab+ciapra
  64.  
  65. OUTB_BUSY equ 4
  66.  
  67.  
  68. ;----------------------------------------------------------------------------
  69. ;
  70. ; NAME
  71. ;     interrupt() - ICR FLG interrupt server
  72. ;
  73. ; SYNOPSIS
  74. ;     void interrupt(struct PLIPBase *)
  75. ;                    A1
  76. ;
  77. ; FUNCTION
  78. ;     This is called from CIA resource on the receipt of an parallel port
  79. ;     FLG line interrupt. This is the case if the other side starts
  80. ;     transmission and writes the first byte to our port.
  81. ;
  82. ;     We recognise this here and propagate the information to the server
  83. ;     task by Signal()ing it and by setting the PLIPB_RECEIVING bit
  84. ;     in the flags field.
  85. ;
  86. ;----------------------------------------------------------------------------
  87.  
  88. _interrupt:
  89.     
  90.     btst    #PLIPB_RECEIVING,pb_Flags(a1)  
  91.     bne.s   setack          
  92.                     ; PLIPF_RECEIVING&pb_Flags == 0
  93.  
  94.     move.b  StatusReg,d0            ; PAR_STATUS==CIAF_PRTRPOUT ? 
  95.     andi.b  #7,d0
  96.     cmp.b   #2,d0   
  97.     bne.s   skipint
  98.  
  99.     bset    #PLIPB_RECEIVING,pb_Flags(a1)
  100.     move.l  pb_IntSigMask(a1),d0
  101.     movea.l pb_SysBase(a1),a6       ; Signal
  102.     movea.l pb_Server(a1),a1
  103. gosig:  
  104. ;       movem.l a6,-(sp)                ; ExecBase is not in a6...
  105.     JSRLIB  Signal
  106. ;       movem.l (sp)+,a6
  107. skipint: 
  108.     moveq #0,d0                     ; set Z flag => next server
  109.     rts
  110.  
  111. setack:                                 ; PLIPF_RECEIVING&pb_Flags != 0
  112.     bset.b  #PLIPEB_NIBBLEACK,(pb_ExtFlags+1)(a1)
  113.     moveq #0,d0                     ; set Z flag => next server
  114.     rts
  115.  
  116.  
  117. ;----------------------------------------------------------------------------
  118. ;
  119. ; NAME
  120. ;     send_bit() - writes one byte to the parallel port
  121. ;
  122. ; SYNOPSIS
  123. ;     ULONG send_bit(UBYTE *TimeoutSet, UBYTE)
  124. ;                       a2               d0
  125. ;
  126. ;
  127. ; FUNCTION
  128. ;     This function writes one byte to the parallel port.
  129. ;     Implemented in a really stupid way (using loops),
  130. ;     but I can't see how I could use signals or interrupts
  131. ;     without changing the protocol.
  132. ;
  133. ; RESULT -> D0, Z
  134. ;     0         All went right
  135. ;     1         Timeout
  136. ;       
  137. ;----------------------------------------------------------------------------
  138. _send_bit:
  139.     move.l  d0,d1                   ; data -> d1
  140.  
  141.     andi.b  #$0f,d0                 ; first 4 bits 0-3
  142.     move.b  d0,OutReg
  143.     bset    #OUTB_BUSY,d0           ; BUSY on
  144.     move.b  d0,OutReg               ; bset #OUTB_BUSY,OutReg won't work 
  145.  
  146. loop1:                                  ; wait for BUSY on or Timeout
  147.     tst.b   (a2)
  148.     bne     snd_timeout
  149.     btst    #CIAB_PRTRBUSY,StatusReg
  150.     beq.s   loop1
  151.  
  152.     lsr.b   #4,d1                   ; last bits 4-7
  153.     bset    #OUTB_BUSY,d1
  154.     move.b  d1,OutReg
  155.     bclr    #OUTB_BUSY,d1           ; BUSY off
  156.     move.b  d1,OutReg               ; bclr #OUTB_BUSY,OutReg won't work
  157.  
  158. loop2:
  159.     tst.b   (a2)                    ; wait for BUSY off or Timeout
  160.     bne     snd_timeout
  161.     btst    #CIAB_PRTRBUSY,StatusReg
  162.     bne.s   loop2
  163.  
  164.     
  165. ;allright:
  166.     moveq   #0,d0                   ; return OK
  167.     rts
  168.  
  169. snd_timeout: 
  170.     moveq   #1,d0                   ; return TIMEOUT
  171.     rts
  172.  
  173. ;----------------------------------------------------------------------------
  174. ;
  175. ; NAME
  176. ;     receive_bit() - reads one byte from the parallel port
  177. ;
  178. ; SYNOPSIS
  179. ;     ULONG receive_bit(volatile UBYTE *timeoutset, UBYTE *ExtFlags + 1, UBYTE busystate)
  180. ;                               a2                        a0                     d2
  181. ;
  182. ;
  183. ; FUNCTION
  184. ;     This function reads one byte from the parallel port, 
  185. ;     relying on messages sent by the interrupt. 
  186. ;
  187. ; ARGUMENTS
  188. ;
  189. ;     timeoutset        : the byte at this address is checked periodically
  190. ;                         and the function returns an error if a non-null
  191. ;                         value is found there.
  192. ;     ExtFlags+1        : The bit 1 of this byte contains the flag NIBBLEACK
  193. ;                         set by the interrupt = ((UBYTE *)pb->pb_ExtFlags)+1
  194. ;     busystate         : The state in which the BUSY output line was left
  195. ;                         by a previous call of this function of hwrecv.
  196. ;                         value : 0x00 or 0x10
  197. ;
  198. ; RESULT
  199. ;  Dans d0 (et dans Z)
  200. ;     0         All went right
  201. ;     1         Timeout 
  202. ;  Dans d1 : 
  203. ;     Le bit lu
  204. ;
  205. ; NOTE
  206. ;     a0 and a2 are left untouched ! guaranteed  !
  207. ;     I've tried a version using signals sent by the interrupt instead
  208. ;     of those stupid loops, but it's too slow. (about 3 times as slow)
  209. ;
  210. ;----------------------------------------------------------------------------
  211. _receive_bit:
  212.  
  213. WAITFOR_NIBBLEACK       MACRO   ; should be a function, but I'm looking for speed               
  214. rloop\@:
  215.     tst.b   (a2)
  216.     bne     rcv_timeout
  217.     btst.b  #PLIPEB_NIBBLEACK,(a0)
  218.     beq     rloop\@
  219.     
  220.     bclr.b  #PLIPEB_NIBBLEACK,(a0)
  221.     ENDM
  222.  
  223. RECV_ACKNOWLEDGE        MACRO   ; invert the state of the output BUSY line (uses d2)
  224.     bchg    #OUTB_BUSY,d2
  225.     move.b  d2,OutReg
  226.     ENDM                            
  227.  
  228.  
  229.     WAITFOR_NIBBLEACK
  230.  
  231.     ; d1 = in_sbp()
  232.     clr.b   d1
  233.  
  234.     move.b  StatusReg,d1            ; statusreg -> d1 
  235.     RECV_ACKNOWLEDGE
  236.  
  237.     andi.b  #7,d1
  238.  
  239.     WAITFOR_NIBBLEACK
  240.  
  241.     ; d1 |= in_sbp()<<3
  242.     move.b  StatusReg,d0
  243.     RECV_ACKNOWLEDGE
  244.  
  245.     andi.b  #7,d0
  246.     lsl.b   #3,d0
  247.     eor.b   d0,d1
  248.  
  249.     WAITFOR_NIBBLEACK       
  250.  
  251.     ; d1 |= in_sbp() << 6
  252.     move.b  StatusReg,d0
  253.     RECV_ACKNOWLEDGE
  254.  
  255.     andi.b  #3,d0
  256.     lsl.b   #6,d0
  257.     eor.b   d0,d1
  258.  
  259. ;allright:
  260.     moveq   #0,d0                   ; return OK
  261.     rts
  262.  
  263. rcv_timeout: 
  264.     moveq  #1,d0                    ; return TIMEOUT
  265.     rts
  266.  
  267.  
  268. ;----------------------------------------------------------------------------
  269. ;
  270. ; NAME
  271. ;    hwrecv(struct PLIPBase *) - receive a frame from the parallel port
  272. ;           a0
  273. ;
  274. ; FUNCTION
  275. ;    First allocate a signal from the current task and set pb_ModSigMask and
  276. ;    pb_ModTask for the interrpution. 
  277. ;    Then, it acknowledge the beginning of a packet by sending 0x02 (SELECT),
  278. ;    gets the size, the data and the checksum (one byte). 
  279. ;    
  280. ; RESULT
  281. ;    boolean (ULONG) 
  282. ;    TRUE => OK
  283. ;    FALSE => ERROR
  284. ;
  285. ;----------------------------------------------------------------------------
  286. _hwrecv:
  287.     movem.l d2-d7/a2-a5,-(sp)
  288.  
  289.     movea.l a0,a5                   ; pb -> a5
  290.     lea.l   pb_TimeoutSet(a5),a2    ; &pb->pb_TimeoutSet -> a2 (pour receive_bit)
  291.     lea.l   (pb_ExtFlags+1)(a5),a0  ; &pb->pb_ExtFlags+1 -> a0 (pour receive_bit)
  292.     movea.l pb_Frame(a5),a3         ; frame 
  293.     lea.l   pf_DstAddr(a3),a4       ; &frame->data -> a4
  294.     lea.l   pf_Size(a3),a3          ; &frame->pf_Size -> a3
  295.     moveq   #0,d2                   ; state of the BUSY output (pour receive_bit)
  296.  
  297.     moveq   #0,d4                   ; retval = d4 (ERROR=0)
  298.  
  299.     bclr.b  #PLIPEB_NIBBLEACK,(a0)
  300.  
  301.     moveq   #2,d0
  302.     move.b  d0,OutReg               ; Acknowledge
  303.  
  304.     clr.w   d5                      ; d5 = data_len
  305.  
  306.     jsr     _receive_bit            ; Lower part of Length
  307.     bne.s   ffrec_error
  308.     move.b  d1,d5                   ; -> d5 (low)
  309.  
  310.  
  311.     jsr     _receive_bit            ; Upper part of Length
  312.     bne.s   ffrec_error
  313.     lsl.w   #8,d1
  314.     eor.w   d1,d5
  315.     beq.s   ffrec_error             ; size == 0 ?
  316.  
  317.  
  318.     move.w  d5,(a3)                 ; d5 -> pf_Size 
  319.  
  320.     move.l  pb_MTU(a5),d0
  321.     add.w   #PKTFRAMESIZE_2,d0
  322.     cmp.w   d5,d0
  323.     blt.s   ffrec_error             ; d0<d5=data_len Too big ? 
  324.     tst.w   d5
  325.     blt.s   ffrec_error             ; d5 < 0 ??
  326.  
  327.  
  328.     subq.w  #1,d5                   ; d5 = size-1 (better for loops)
  329.     move.w  d5,d6                   ; d6 = size-1 (for checksum loop)
  330. dataloop:                               ; do {
  331.     jsr     _receive_bit
  332.     bne.s   ffrec_error
  333.     move.b  d1,(a4)+
  334.     dbf.w   d5,dataloop             ; }while(--d5!=-1);
  335.  
  336.  
  337.     clr.b   d5                      ; Checksum -> d5
  338. checkloop:                              ; do {
  339.     add.b   -(a4),d5
  340.     dbf.w   d6,checkloop            ; }while(--d6!=-1);
  341.  
  342.     jsr     _receive_bit
  343.     bne.s   ffrec_error
  344.  
  345.  
  346.     cmp.b   d5,d1                   ; Checksum OK ?
  347.     bne.s   ffrec_error
  348.  
  349.                     ; Clean up the port
  350.     moveq   #1,d4                   ; return OK
  351.  
  352.     tst.b   d2                      ; d2==0 ? 
  353.     beq.s   ffrec_error             ; Not an error. Skipping
  354.  
  355. lineloop:                               ; Clean the line. 
  356.     tst.b   (a2)
  357.     bne     ffrec_error             ; The retval stays to TRUE
  358.     btst.b  #PLIPEB_NIBBLEACK,(a0)
  359.     beq     lineloop
  360.  
  361. ffrec_error:
  362.     clr.b   OutReg
  363.     bclr    #PLIPB_RECEIVING,pb_Flags(a5)
  364.     move.l  d4,d0                   ; return retval
  365. frrec_end:
  366.     movem.l (sp)+,d2-d7/a2-a5
  367.     rts
  368.  
  369. ;----------------------------------------------------------------------------
  370. ;
  371. ; NAME
  372. ;    hwsend(struct PLIPBase *) - receive a frame to the parallel port
  373. ;           a0
  374. ;
  375. ; FUNCTION
  376. ;    First, it triggers the other side by sending an ACK signal, and
  377. ;    then it waits for an answer (a SEL signal).
  378. ;    It sends : two bytes containing the size, the data, and a crc (1 byte)
  379. ;    
  380. ; RESULT
  381. ;    boolean (ULONG) 
  382. ;    TRUE => OK
  383. ;    FALSE => ERROR
  384. ;
  385. ;----------------------------------------------------------------------------
  386. _hwsend:
  387.     movem.l d4-d6/a2-a6,-(sp)
  388.  
  389.     movea.l a0,a5                   ; pb -> a5
  390.     lea.l   pb_TimeoutSet(a5),a2    ; &pb->pb_TimeoutSet -> a2 (for send_bit)
  391.     movea.l pb_Frame(a5),a3         ; frame 
  392.     lea.l   pf_DstAddr(a3),a4       ; data -> a4
  393.     lea.l   pf_Size(a3),a3          ; *size -> a3
  394.     lea.l   pb_Flags(a5),a0         ; *pb_Flags -> a0 (temporary !)
  395.  
  396.     moveq   #0,d4                   ; d4=retval=FALSE (error)
  397.  
  398.     btst    #PLIPB_RECEIVING,(a0)
  399.     bne     snd_error               ; Collision ?
  400.  
  401.     moveq   #8,d0
  402.     move.b  d0,OutReg               ; Trigger
  403.  
  404. sndloop0:
  405.     tst.b   (a2)                    ; TimeoutSet ?
  406.     bne     snd_error
  407.     btst    #PLIPB_RECEIVING,(a0)
  408.     bne     snd_error
  409.     btst    #CIAB_PRTRSEL,StatusReg
  410.     beq.s   sndloop0                ; }while(!(StatusReg&CIAF_PRTRSEL));
  411.  
  412.     movea.l pb_CIAABase(a5),a6      ; CIAABase -> a6
  413.     moveq   #CIAICRF_FLG,d0
  414.     JSRLIB  AbleICR                 ; Disable interrupt
  415.  
  416.     move.w  (a3),d5                 ; data_len -> d5
  417.     move.b  d5,d0                   ; Send lower byte of Size
  418.     jsr     _send_bit
  419.     bne     snd_inton
  420.  
  421.     move.w  d5,d0
  422.     lsr.w   #8,d0                   ; Send upper byte of Size
  423.     jsr     _send_bit
  424.     bne     snd_inton
  425.  
  426.     subq.w  #1,d5                   ; d5=size-1 (for loops)
  427.     move.w  d5,d6                   ; d6=size-1
  428.  
  429. sndmainloop:                            ; do{
  430.     move.b  (a4)+,d0
  431.     jsr     _send_bit
  432.     bne     snd_inton
  433.     dbf.w   d5,sndmainloop          ; }while(--d5!=-1)
  434.  
  435.     clr.b   d0                      ; checksum -> d0
  436. sndchecksum:
  437.     add.b   -(a4),d0
  438.     dbf.w   d6,sndchecksum          ; }while(--d6!=-1)
  439.  
  440.     jsr     _send_bit       
  441.     bne     snd_inton
  442.  
  443.     moveq   #1,d4                   ; retval = TRUE (OK)
  444.  
  445. snd_inton:
  446.     moveq   #CIAICRF_FLG,d0
  447.     JSRLIB  SetICR                  ; Clear interrupt
  448.     move.w  #CIAICRF_FLG|CIAICRF_SETCLR,d0
  449.     JSRLIB  AbleICR                 ; Enable interrupt
  450.  
  451. snd_error:
  452.     clr.b   OutReg                  ; put the line back into order
  453.     move.b  d4,d0
  454.  
  455. snd_end:
  456.     movem.l (sp)+,d4-d6/a2-a6
  457.     rts
  458.  
  459.      end
  460.